
const gjjTokenUrl   = "https://t.51gjj.com/gjj/getToken";
const getOrderSnUrl = "https://t.51gjj.com/gjj/getOrderSn";
const getGjjH5Url   = "https://t.51gjj.com/gjj";
const gjjDataUrl    = "http://b.jianbing.com/gjj_v3/gjj/fetch_manual";
const getGjjDataUrl        = "https://t.51gjj.com/gjj/getGjjData";

var myRedis = require('./myRedis').config('6379', '127.0.0.1');
var myAxios =  require('./myAxios');

var fs          =  require('fs');
var config      =  require('config');
var parCfg      =  config.get('partnerConfig');
var NodeRSA     =  require('node-rsa');
var express     =  require('express');
var querystring =  require('querystring');
// var nodeDB      =  require('./db');
var md5         =  require('md5');
var url         =  require('url');
var request     =  require('request');
var axios       =  require('axios');
var crypto      =  require('crypto');

function getToken(callbackA,callbackB){
    let redisClient =  myRedis.config('6379', '127.0.0.1').create().redis;
    let data = [];
    data['timestamp'] = +new Date;
    data['appKey'] = parCfg.reptileAppKey;
    let appSecret = parCfg.reptileAppSecret;
    let sign = createSign(data,appSecret);
    let params = {
        "sign":sign,
        "params":{
            "appKey":data['appKey'],
            "timestamp":data['timestamp']
        }
    }

    redisClient.get('node_gjj_wld_token', function(error, res) {

        if(error) {
            console.log(error);
        } else {
            // console.log('query redis:'+res);
            if(res===null){
                //token过期
                //redis锁
                redisClient.set('node_gjj_wld_token','lock',function(error,result){
                    if(error){
                        console.log(error);
                        redisClient.end(true);
                    }else{
                        //锁好后开始请求token
                        //锁的有效时间30秒
                        redisClient.expire('node_gjj_wld_token',30,function(error,result){
                            if(error){
                                console.log('redis expire lock 30 fail '+error);
                            }else{
                                // console.log('redis expire lock 30 success '+result);

                                axios.all([
                                    axios.post(gjjTokenUrl,params,{headers: {'Content-Type': 'application/json'}})
                                ]).then(axios.spread((axiosRes) => {
                                    if(axiosRes.data.code==0){

                                        let token = axiosRes.data.data.token;

                                        redisClient.set('node_gjj_wld_token',token,function(error,result){
                                            if(error){
                                                console.log(error);
                                                redisClient.end(true);
                                            }else{

                                                // redisClient.get('node_gjj_wld_token',redis.print);
                                                //token过期时间
                                                redisClient.expire('node_gjj_wld_token',7200,function(error,result){
                                                    if(error){
                                                        console.log('redis expire node_gjj_wld_token fail '+error);
                                                    }else{
                                                        // console.log('redis expire node_gjj_wld_token success '+result);
                                                    }
                                                    redisClient.end(true);
                                                });

                                                // console.log('wld new token '+token);
                                                callbackA(token,callbackB);
                                            }
                                        });
                                    }
                                })).catch(error => {
                                    //请求token失败
                                    console.log('get token fail '+error);
                                    redisClient.end(true);
                                });
                            }
                            // redisClient.end(true);
                        });

                    }
                });

            }else{
                if(res == 'lock'){
                    //遇到锁
                    let insRedis = myRedis.create();
                    let myTimer = setInterval(function() {
                        insRedis.redis.get('node_gjj_wld_token', function (err, reply) {
                            if(reply == 'lock') {
                                console.log('I get token lock: ' + reply.toString());
                            } else {
                                clearTimeout(myTimer);

                                callbackA(reply,callbackB);
                                insRedis.end(true);
                            }
                        });
                    }, 1000);

                }else{
                    //没有锁
                    // console.log('get token success ' + res);
                    callbackA(res,callbackB);
                    // flush();
                    redisClient.end(true);
                }
            }
        }

    });
}

async function getTokenToRedis(tokenName,expiresTime,refresh) {
    let token = null;
    const lockName = "token_lock_"+parCfg.cid;
    // const tokenName = "partner_token_"+parCfg.cid;
    let insRedis = myRedis.create();
    let reloading = function (){
        let i = 0;
        return new Promise(resolve=>{
            let myTimer = setInterval(
                async function(){
                    token = await insRedis.get(tokenName);
                    //console.error(token)
                    //console.error('loading modify '+tokenName+':'+token);
                    if(token!==null || i>30){
                        clearTimeout(myTimer);
                        resolve(token);
                    }
                },
                1000
            )}
        );
    }

    token = await insRedis.get(tokenName);
    //console.log('old token is:' + token);

    if (token === null || refresh) {
        let ifSet = await insRedis.set(lockName, 'lock', 'EX', 30, 'NX');
        console.error('ifSet ' + ifSet);
        if (ifSet || refresh) {

            // //获取token
            let data = [];
            data['timestamp'] = +new Date;
            data['appKey'] = parCfg.reptileAppKey;
            let appSecret = parCfg.reptileAppSecret;
            let sign = createSign(data,appSecret);
            //token参数
            let params = {
                "sign":sign,
                "params":{
                    "appKey":data['appKey'],
                    "timestamp":data['timestamp']
                }
            }

            let result = await myAxios.post(gjjTokenUrl,params,{headers:{'Content-Type':'application/json'}});
            if(result){
                if(result.data.code==0){
                    //写入token
                    token = result.data.data.token;
                    await insRedis.set(tokenName, token, 'EX', expiresTime, 'NX');
                    // token = await insRedis.get(tokenName);
                }
            }
            if(typeof token!='string'){
                insRedis.del(lockName);
                token = await reloading();
            }

        } else {
            //遇到锁|等待
            token = await reloading();
        }
    }
    // console.log('new token is:' + token);
    return token;
}

function getOrder(token,callback){
    let data = [];
    data['timestamp'] = +new Date;
    data['appKey']    = parCfg.reptileAppKey;
    data['token']     = token;
    let appSecret     = parCfg.reptileAppSecret;
    let sign = createSign(data,appSecret);

    let params = {
        "sign":sign,
        "params":{
            "appKey":data['appKey'],
            "timestamp":data['timestamp'],
            "token":data['token']
        }
    }
    myAxios.axios.all([
        myAxios.axios.post(getOrderSnUrl,params,{headers: {'Content-Type': 'application/json'}})
    ]).then(myAxios.axios.spread((res) => {
        if(res.data.code==0){
            let order = res.data.data.orderSn;
            // console.log('get order success '+ order);
            callback(token,order);
        }else{
            console.log('get order fail '+ JSON.stringify(res.data));
            callback(res.data);
        }
    })).catch(error => {
        console.log(error);
    });

}

function createOldToken(size){
    if(!size){size=32;}
    //加密
    var token = randomString(size);
    //console.log('token = '+token);
    // token = 'oxFnj5ldW2wemEZI16it0OLZ_6HZdJc1';

    //解密
    // var rsaPrivateFileName  = __projectDir+'/ca/'+partnerCfg.GJJ_RSA_PRIVATE_KEY;
    // var rsaPrivateKeyStr = fs.readFileSync(rsaPrivateFileName).toString('ascii');
    // var dncryptedAccessToken = rsaDecrypt(encryptedAccessToken,rsaPrivateKeyStr);

    return token;
}

function createOldOpenid(num){
    if(!num){num=0;}
    var r = new Array('Q', 'w', 'E', '8', 'a', 'S', '2', 'd', 'Z', 'x', '9', 'c', '7', 'p', 'O', '5', 'i', 'K', '3', 'm', 'j', 'U', 'f', 'r', '4', 'V', 'y', 'L', 't', 'N', '6', 'b', 'g', 'H');
    var b = new Array('q', 'W', 'e', 'A', 's', 'D', 'z', 'X', 'C', 'P', 'o', 'I', 'k', 'M', 'J', 'u', 'F', 'R', 'v', 'Y', 'T', 'n', 'B', 'G', 'h');
    var l = r.length;
    var s = 12;
    var buf = new Array();
    var charPos = 32;
    for(var i=0;i<charPos;i++){
        buf[i]=' ';
    }
    while (Math.round(num / l) > 0) {
        buf[--charPos] = r[Math.round(num % l)];
        num /= l;
    }
    buf[--charPos] = r[Math.round(num % l)];
    buf = buf.join('');
    var str = buf.substr(charPos, (32 - charPos));
    //不够长度的自动随机补全
    if ( str.length < s) {
        var sb = '';
        for (i = 0; i < s - str.length; i++) {
            sb += b[Math.round(Math.random()*(b.length-1))];
        }
        str += sb;
    }
    return str;
}

function sendJsonPost(serUrl, params, callback){
    axios.all([
        axios.post(serUrl,params,{headers: {'Content-Type': 'application/json'}})
    ]).then(axios.spread((axiosRes) => {
        callback('',axiosRes.data);
    })).catch(error => {
        callback(error,'');
    });
}

function sendGet(serUrl, params, callback){
    if(params){
        let h5Url = "";
        for(x in params){
            if(!h5Url){
                h5Url += '?'+x+'='+params[x];
            }else{
                h5Url += '&'+x+'='+params[x];
            }
        }
        serUrl = serUrl + h5Url;
    }
    // console.log(serUrl);
    axios.all([
        axios.get(serUrl)
    ]).then(axios.spread((axiosRes) => {
        callback(axiosRes.data);
    })).catch(error => {
        console.log(error);
    });
}

function randomString (size){
    if(!size){size=32;}
    var a = "-_0987654321asdfghjklzxcvbnmqwertyuiopASDFGHJKLZXCVBNMQWERTYUIOP";
    var len = a.length;
    var result = '';
    for(var i=0; i<size; i++) {
        result += a[0+Math.round(Math.random()*len)];
    }
    return result;
}

function rsaEncrypt(str, rsaPublicKeyStr){
    str = base64Encode(str);
    var rsaEncodeData = "";
    try {
        var publickey = new NodeRSA(rsaPublicKeyStr);
        rsaEncodeData = publickey.encrypt(str,'base64');
    }catch(err) {
        console.log('rsa加密: '+err);
    }
    return rsaEncodeData;
}

function rsaDecrypt(rsaEncodeData, rsaPrivateKeyStr){

    //rsaPrivateKeyStr = rsaPrivateKeyStr.replace(/\n/g,'');
    //rsaPrivateKeyStr = rsaPrivateKeyStr.replace(/\r/g,'');


    let privateKey = {
        "key":rsaPrivateKeyStr,
        "passphrase":"",
        "padding":crypto.constants.RSA_NO_PADDING
    }

   // rsaEncodeData = base64Decode(rsaEncodeData);
    var rsaDecodeData = "";
    try {
        // let privatekey = new NodeRSA(rsaPrivateKeyStr);
        // rsaDecodeData = privatekey.decrypt(rsaEncodeData,'utf8');

        console.log(privateKey);
        console.log(new Buffer(rsaEncodeData).length);
        console.log(rsaEncodeData);
        let buf = new Buffer(rsaEncodeData);
        let step = 64;
        let box = new Array();
        let x = 0;
        for(var i=0; i<buf.length; i+=step){
            box[x] = crypto.privateDecrypt(privateKey,new Buffer(rsaEncodeData.substr(i,step)));
            ++x;
        }
        rsaDecodeData = box.join('');

        //rsaDecodeData = crypto.privateDecrypt(privateKey,new Buffer(rsaEncodeData));
    }catch(err){
        console.log('rsa解密: '+err);
    }
    return rsaDecodeData;
}

function base64Encode(str) {
    let buf = new Buffer(str);
    let base64str = buf.toString('base64');
    base64str = base64str.replace(/\+/g,'-');
    base64str = base64str.replace(/\//g,'_');
    base64str = base64str.replace(/=/g,'');
    return base64str;
}

function base64Decode(base64str) {
    base64str = base64str.replace(/-/g,'+');
    base64str = base64str.replace(/_/g,'/');
    let mod4 = base64str.length % 4;
    if(mod4){
        base64str += '===='.substr(mod4);
    }
    let buf = new Buffer(base64str);
    let str = buf.toString('utf8');
    return str;
}

function getJsonPostParams(req){
    var params = "";
    req.on('data', function(chunk){
        params += chunk;
    });
    req.on('end', function(){
        params = querystring.parse(params);
    });
    if(typeof params=="string" && params==""){
        return false;
    }
    if(typeof params=="array" && params.length==0){
        return false;
    }
    return params;
}

function getUrlParams(req){
    var params  = "";
    params = url.parse(req.url, true).query;
    return params;
}

function getParams(req, key, def){
    var params = "";
    if(typeof req.body[key]!='undefined'){
        params = req.body[key];
    }else if(typeof url.parse(req.url, true).query[key]!='undefined'){
        params = url.parse(req.url, true).query[key];
    }
    if(!params){
        params = def;
    }
    return params;
}

function getValue(data, key, def){
    if(typeof def=='undefined'){
        def='';
    }
    var params = "";
    if(typeof data!='undefined' && typeof data[key]!='undefined'){
        params = data[key];
    }
    if(!params){
        params = def;
    }
    return params;
}

function urlGetValue(data, key, def, url){

}

function getBodyParams(req, key, def){
    var params = typeof def=='undefined' ? "":def;
    params = typeof req.body[key]=='undefined' ? params:req.body[key];
    return params;
}

function createSign(params,appSecret,version){
    var keys = new Array();
    var i = 0;

    for(x in params){
        if(params[x]){
            keys[i] = x;
            ++i;
        }
    }
    keys.sort();
    // console.log(keys);
    var sp = '';
    var stringA = '';
    var value;
    for (var x=0; x<keys.length; x++){
        if(keys[x]=='sign' || keys[x]=='signType'){
            continue;
        }
        value = params[keys[x]];

        if(value){
            stringA += sp + keys[x] + '=' + value;
            sp = '&';
        }
    }
    //差异appSecret  &  appsecret
    let appSecretKey;
    if(!version){
        //爬虫端
        appSecretKey = 'appSecret';
    }else{
        //原来服务端
        appSecretKey = 'appsecret';
    }
    stringA += sp + appSecretKey+'=' + appSecret;
    var md5StringA = md5(stringA);
    return md5StringA.toUpperCase();
}

function notify(url,params){

    let content = "";
    for(x in params){
        if(!content){
            content += ('"'+x+'":"'+params[x]+'"');
        }else{
            content += (',"'+x+'":"'+params[x]+'"');
        }
    }

    content = '{'+content+'}';

    //是否加密通知
    //判断依据是否有合作方预留的公钥
    if(parCfg.RSA_PARTNER_PUBLIC_KEY){
        let rsaPublicFileName  = __projectDir+'/ca/'+parCfg.RSA_PARTNER_PUBLIC_KEY;
        let rsaPublicKeyStr = fs.readFileSync(rsaPublicFileName).toString('ascii');
        content = rsaEncrypt(content,rsaPublicKeyStr);
    }

    axios.all([
        axios.post(url,JSON.parse(content),{headers: {'Content-Type': 'application/json'}})
    ]).then(axios.spread((res) => {
        let data = res.data;
        if(data.code==0){
            // console.log(data);
        }else{
            console.log('node wld notify fail errCode=101 '+ JSON.stringify(data));
        }
    })).catch(error => {
        console.log('node wld notify fail errCode=102 '+error);
    });
}

function getGjjMD5(orderSn,callback){
    getGjjData(orderSn,function(err,data,callback){
        if(!err){
            // console.log(data);
            if(data.code==0){
                // let name   = "";
                let ID     = "";
                let name   = "";
                let cityId = "";
                let ifLoan = false;

                if(data.data.gjjData.data.gjj_data){
                    let gjjDataList = data.data.gjjData.data.gjj_data;
                    let loanDataList = data.data.gjjData.data.loan_data;
                    if(gjjDataList.length>0){
                        for(let i=0; i<gjjDataList.length; i++){
                            if(gjjDataList[i].gjj_account_analyzed_data.newest_account == 1){
                                ID     =  gjjDataList[i].gjj_brief.ID;
                                name   =  gjjDataList[i].gjj_brief.name;
                                cityId =  data.data.gjjData.cid;
                            }
                        }
                    }
                    if(loanDataList.length>0){
                        ifLoan = true;
                    }
                }

                let params = new Array();
                //参与md5的参数
                params['ID']     = ID;
                params['cityId'] = cityId;
                let gjjMD5 =  paramsSign(params);

                //有用到的参数
                params['name']   = name;
                params['ifLoan'] = ifLoan;

                callback(false,gjjMD5,params);
            }else{
                callback(data.msg);
            }
        }else{
            callback(err,'',[]);
        }
    },callback);
}

function getGjjData(orderSn,callback2,callback3){
    getToken(
        function(token,callback){
            //它
            callback(token,orderSn,function(err,data){
                if(!err){
                    //成功拿到数据后的操作
                    if(typeof callback3=='function'){
                        callback2('',data,callback3);
                    }else{
                        callback2('',data);
                    }
                }else{
                    //报错
                    callback2(err,'');
                }

            });
        },
        //等于它
        function (token,orderSn,callback){

            let params = {
                'appKey':parCfg.reptileAppKey,
                'timestamp':+new Date,
                'token':token,
                'orderSn':orderSn
            }
            let sign = createSign(params,parCfg.reptileAppSecret);

            let option = {
                'type':'gjj',
                'sign':sign,
                'params':params
            }
            sendJsonPost(getGjjDataUrl,option,function(err,data){
                if(!err){
                    callback('',data);
                }else{
                    callback(err,'');
                }
            });
        }
    );
}

function paramsSign(params){
    let keys = new Array();
    let i = 0;
    for(x in params){
        if(params[x]){
            keys[i] = x;
            ++i;
        }
    }
    keys.sort();
    let sp = '';
    let stringA = '';
    let value;
    for (var x=0; x<keys.length; x++){

        value = params[keys[x]];

        if(value){
            stringA += sp + keys[x] + '=' + value;
            sp = '&';
        }
    }
    let md5StringA = md5(stringA);
    let gjjMD5 =  md5StringA.toUpperCase();
    return gjjMD5
}

//rsa加密
//rsa解密
//openid生成
//token生成

//接口丢出
exports.getToken = getToken;
exports.getOrder = getOrder;
exports.getGjjData = getGjjData;
exports.createOldToken = createOldToken;
exports.createOldOpenid = createOldOpenid;

exports.rsaEncrypt = rsaEncrypt;
exports.rsaDecrypt = rsaDecrypt;
exports.base64Encode = base64Encode;
exports.base64Decode = base64Decode;
exports.getJsonPostParams = getJsonPostParams;

exports.getParams = getParams;
exports.getValue = getValue;
exports.urlGetValue = urlGetValue;
exports.getBodyParams = getBodyParams;
exports.getUrlParams = getUrlParams;
exports.createSign = createSign;

exports.sendJsonPost = sendJsonPost;
exports.sendGet = sendGet;

exports.notify = notify;
exports.getGjjMD5 = getGjjMD5;
exports.getTokenToRedis = getTokenToRedis;



// const makeRequest = async () => {
//     const value1 = await promise1()
//     const value2 = await promise2(value1)
//     return promise3(value1, value2)
// }